package com.ybear.ybcomponent.widget.dialog

import android.app.ActionBar
import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.content.DialogInterface
import android.content.DialogInterface.OnShowListener
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.Point
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Message
import android.view.ActionMode
import android.view.ContextMenu
import android.view.Gravity
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.Menu
import android.view.MenuItem
import android.view.MotionEvent
import android.view.SearchEvent
import android.view.View
import android.view.ViewGroup.LayoutParams
import android.view.Window
import android.view.WindowManager
import android.view.accessibility.AccessibilityEvent
import android.widget.PopupWindow
import androidx.annotation.ColorRes
import androidx.annotation.IdRes
import androidx.annotation.RequiresApi
import androidx.annotation.StringRes
import androidx.core.view.WindowCompat
import com.ybear.ybcomponent.Utils
import com.ybear.ybcomponent.Utils.Companion.drawToBitmap
import com.ybear.ybcomponent.widget.dialog.touch.DialogTouchEventHelper
import kotlin.collections.set

/**
 * Dialog 实现类的基类，封装了 Dialog 的常见操作和属性。
 *
 * **创建 Dialog:**
 *
 *  * 使用 [com.ybear.ybcomponent.widget.dialog.Dialog.with] 方法链式调用创建：
 *     ```kotlin
 *     Dialog.with(context)
 *         .setLayout(R.layout.dialog_example)
 *         .show()
 *     ```
 *  * 继承 DialogOption 并使用 DialogConfig 创建：
 *     ```kotlin
 *     class MyDialog(context: Context) : DialogOption() {
 *         init {
 *             DialogConfig(this, context).apply {
 *                 setLayout(R.layout.dialog_example)
 *                 create()
 *             }
 *         }
 *     }
 *     ```
 *
 * **继承 DialogOption:**
 *
 *  * 可以继承 DialogOption 来自定义 Dialog 的行为和样式。
 *     ```kotlin
 *     class MyCustomDialog(context: Context) : DialogOption() {
 *         // ... 自定义 Dialog 的逻辑
 *     }
 *     ```
 */
abstract class DialogOption :
    DialogInterface,
    OnShowListener,
    DialogInterface.OnCancelListener,
    DialogInterface.OnDismissListener,
    DialogInterface.OnKeyListener, DialogInterfaceHelper {

    companion object {
        @JvmStatic
        private val DIALOG_INVALID_SIZE = Int.MIN_VALUE
    }

    private var mContext: Context? = null
    private var mDialog: DialogX? = null
    private var mDialogConfig: DialogConfig? = null
    private var mDialogTouchEventHelper = DialogTouchEventHelper()
    private val mOnShowListeners: MutableMap<Int, OnShowListener> = HashMap()
    private val mOnCancelListeners: MutableMap<Int, DialogInterface.OnCancelListener> = HashMap()
    private val mOnDismissListeners: MutableMap<Int, DialogInterface.OnDismissListener> = HashMap()
    private val mOnKeyListeners: MutableMap<Int, DialogInterface.OnKeyListener> = HashMap()
    private val mViewXY = intArrayOf(0, 0)
    private val defaultDialogSize = Point(DIALOG_INVALID_SIZE, DIALOG_INVALID_SIZE)

    open var id = 0
    open val context: Context? get() = mContext
    open val window: Window? get() = mDialog?.window
    open val resources: Resources? get() = mDialogConfig?.resources
//    open val childView: View? get() = mDialogConfig?.childView
//    open val attributes: LayoutParams? get() = mDialogConfig?.attributes
//    open val cornerRadius: CornerRadius? get() = mDialogConfig?.cornerRadius
    open val widthByDecorView: Int get() = window?.decorView?.width ?: 0
    open val heightByDecorView: Int get() = window?.decorView?.height ?: 0
    open val decorViewX: Int get() = mViewXY[0]
    open val decorViewY: Int get() = mViewXY[1]
    @get:RequiresApi(api = Build.VERSION_CODES.M)
    open val searchEvent: SearchEvent? get() = mDialog?.searchEvent
    var buildLayoutParams: LayoutParams? = null

    internal fun initOption(config: DialogConfig) {
        config.mDialog.let {
            mContext = context
            mDialogConfig = config
            //初始Dialog
            id = it.hashCode()
            it.setDialogInterfaceHelper( this )
            it.setOnShowListener( this )
            it.setOnCancelListener( this )
            it.setOnDismissListener( this )
            it.setOnKeyListener( this )
            mDialog = it
            mDialogTouchEventHelper.initDialog( mDialog )
            mDialogTouchEventHelper.dialogOption = this
        }
    }

    /**
     * 更新 Dialog 的宽度或高度属性，支持可选的平滑动画。
     *
     * @param attr WindowManager.LayoutParams 对象，用于设置 Dialog 的属性。
     * @param isWidth 如果要更新宽度，则为 true；如果要更新高度，则为 false。
     * @param targetValue 目标宽度或高度值。
     */
    private fun updateAttr(attr: WindowManager.LayoutParams, isWidth: Boolean,
                           targetValue: Int) {
        if ( isWidth ) attr.width = targetValue else attr.height = targetValue
        window?.setLayout( attr.width, attr.height )
//        val change = Consumer<Int> {
//            if (isWidth) attr.width = it else attr.height = it
//            window?.attributes = attr
//        }
//        if (smoothAnimation) {
//            ValueAnimator.ofInt(
//                if (isWidth) attr.width else attr.height,
//                targetValue
//            ).apply {
//                interpolator = DecelerateInterpolator()
//                setDuration(duration).apply {
//                    addUpdateListener { change.accept(it.animatedValue as Int) }
//                    start()
//                }
//            }
//            return
//        }
//        change.accept(targetValue)
    }

    /**
     * 更新 Dialog 的尺寸（宽度和高度），支持可选的平滑动画。
     *
     * @param width Dialog 的新宽度，如果不需要更改宽度，请传递 [DIALOG_INVALID_SIZE]。
     * @param height Dialog 的新高度，如果不需要更改高度，请传递 [DIALOG_INVALID_SIZE]。
     */
    open fun updateDialogSize(width: Int, height: Int) {
        window?.attributes?.let { attr ->
            if (width != DIALOG_INVALID_SIZE) {
                updateAttr( attr, true, width )
            }
            if (height != DIALOG_INVALID_SIZE) {
                updateAttr( attr, false, height )
            }
        }
    }

    /**
     * 更新 Dialog 的宽度，支持可选的平滑动画。
     *
     * @param width Dialog 的新宽度。
     */
    open fun updateDialogWidth(width: Int) {
        updateDialogSize( width, defaultDialogSize.y )
    }

    /**
     * 更新 Dialog 的高度，支持可选的平滑动画。
     *
     * @param height Dialog 的新高度。
     */
    open fun updateDialogHeight(height: Int) {
        updateDialogSize( defaultDialogSize.x, height )
    }

    /**
     * 重置 Dialog 到其原始尺寸，支持可选的平滑动画。
     */
    open fun resetDialogSize() {
        updateDialogSize( defaultDialogSize.x, defaultDialogSize.y )
    }

    /**
     * 设置 Dialog 关闭时发送的消息。
     *
     * @param handler 处理消息的 Handler。
     * @param msg 要发送的消息。
     */
    open fun dismissMessage(handler: Handler?, msg: Message?) {
        handler?.apply { msg?.target = this }
        mDialog?.setDismissMessage(msg)
    }

    /**
     * 设置 Dialog 关闭时发送的消息。
     *
     * @param msg 要发送的消息。
     */
    open fun dismissMessage(msg: Message?) {
        dismissMessage(null, msg)
    }

    /**
     * 设置 Dialog 取消时发送的消息。
     *
     * @param msg 要发送的消息。
     */
    open fun cancelMessage(msg: Message?) {
        mDialog?.setCancelMessage(msg)
    }

    /**
     * 设置 Dialog 取消时的监听器。
     *
     * @param l 取消监听器。
     * @return DialogOption 对象本身，用于链式调用。
     */
    open fun onCancelListener(l: DialogInterface.OnCancelListener?): DialogOption {
        if (l == null) mOnCancelListeners.remove(0) else mOnCancelListeners[0] = l
        return this
    }

    /**
     * 添加 Dialog 取消时的监听器。
     *
     * @param l 取消监听器。
     * @return DialogOption 对象本身，用于链式调用。
     */
    open fun addOnCancelListener(l: DialogInterface.OnCancelListener?): DialogOption {
        l?.apply { mOnCancelListeners[hashCode()] = this }
        return this
    }

    /**
     * 设置 Dialog 关闭时的监听器。
     *
     * @param l 关闭监听器。
     * @return DialogOption 对象本身，用于链式调用。
     */
    open fun onDismissListener(l: DialogInterface.OnDismissListener?): DialogOption {
        if (l == null) mOnDismissListeners.remove(0) else mOnDismissListeners[0] = l
        return this
    }

    /**
     * 添加 Dialog 关闭时的监听器。
     *
     * @param l 关闭监听器。
     * @return DialogOption 对象本身，用于链式调用。
     */
    open fun addOnDismissListener(l: DialogInterface.OnDismissListener?): DialogOption {
        l?.apply { mOnDismissListeners[hashCode()] = this }
        return this
    }

    /**
     * 设置 Dialog 显示时的监听器。
     *
     * @param l 显示监听器。
     * @return DialogOption 对象本身，用于链式调用。
     */
    open fun onShowListener(l: OnShowListener?): DialogOption {
        if (l == null) mOnShowListeners.remove(0) else mOnShowListeners[0] = l
        return this
    }

    /**
     * 添加 Dialog 显示时的监听器。
     *
     * @param l 显示监听器。
     * @return DialogOption 对象本身，用于链式调用。
     */
    open fun addOnShowListener(l: OnShowListener?): DialogOption {
        l?.apply { mOnShowListeners[hashCode()] = this }
        return this
    }

    /**
     * 设置 Dialog 按键事件的监听器。
     *
     * @param l 按键事件监听器。
     * @return DialogOption 对象本身，用于链式调用。
     */
    open fun onKeyListener(l: DialogInterface.OnKeyListener?): DialogOption {
        if (l == null) mOnKeyListeners.remove(0) else mOnKeyListeners[0] = l
        return this
    }

    /**
     * 添加 Dialog 按键事件的监听器。
     *
     * @param l 按键事件监听器。
     * @return DialogOption 对象本身，用于链式调用。
     */
    open fun addOnKeyListener(l: DialogInterface.OnKeyListener?): DialogOption {
        l?.apply { mOnKeyListeners[hashCode()] = this }
        return this
    }

    /**
     * 设置是否允许点击 Dialog 외부区域取消 Dialog。
     *
     * @param enable 如果允许，则为 true；否则为 false。
     * @return DialogOption 对象本身，用于链式调用。
     */
    open fun canceledOnTouchOutside(enable: Boolean): DialogOption {
        mDialog?.setCanceledOnTouchOutside(enable)
        return this
    }

    /**
     * 设置是否允许取消 Dialog。
     *
     * @param enable 如果允许，则为 true；否则为 false。
     * @return DialogOption 对象本身，用于链式调用。
     */
    open fun cancelable(enable: Boolean): DialogOption {
        mDialog?.setCancelable(enable)
        return this
    }

    /**
     * 被状态栏覆盖
     */
    open fun statusBarCovered() : DialogOption {
        window?.apply {
            // 1. 让窗口绘制到状态栏区域（FLAG_LAYOUT_IN_SCREEN + FLAG_LAYOUT_NO_LIMITS）
            addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or
                    WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)

            // 2. Android P+ 支持刘海屏，允许内容延伸到刘海区域
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                attributes.layoutInDisplayCutoutMode =
                    WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
            }

            // 3. 透明状态栏背景（如果你想让状态栏半透明或透明）
            addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
            statusBarColor = Color.TRANSPARENT

            // 4. 将内容贴到屏幕顶端
            setGravity(Gravity.TOP or Gravity.CENTER_HORIZONTAL)

            // 5. 取消 DecorView 的 fitsSystemWindows（Android R+ 用 WindowCompat）
            if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.R ) {
                // Android R+：
                WindowCompat.setDecorFitsSystemWindows( this, false )
            }else {
                @Suppress("DEPRECATION")
                decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
                        View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            }
        }
        return this
    }

    /**
     * 设置音量控制流类型。
     *
     * @param streamType 音量控制流类型。
     * @return DialogOption 对象本身，用于链式调用。
     */
    open fun volumeControlStream(streamType: Int): DialogOption {
        mDialog?.volumeControlStream = streamType
        return this
    }

    open fun getVolumeControlStream(): Int {
        return mDialog?.volumeControlStream ?: -1
    }

    /**
     * 设置 Dialog 的宿主 Activity。
     *
     * @param activity 宿主 Activity。
     * @return DialogOption 对象本身，用于链式调用。
     */
    open fun ownerActivity(activity: Activity): DialogOption {
        mDialog?.setOwnerActivity(activity)
        return this
    }

    /**
     * 获取 Dialog 的宿主 Activity。
     * @return DialogOption 对象本身，用于链式调用。
     */
    open fun getOwnerActivity(): Activity? {
        return mDialog?.ownerActivity
    }

    /**
     * 通过 ID 查找 Dialog 中的 View。
     *
     * @param id View 的 ID。
     * @return 找到的 View，或者 null。
     */
    open fun <T : View?> findViewById(@IdRes id: Int): T? {
        return mDialog?.findViewById(id)
    }

    /**
     * 获取 Dialog 的触摸事件处理器。
     *
     * @return DialogTouchEventHelper 对象。
     */
    open fun getTouchEvent(): DialogTouchEventHelper {
        return mDialogTouchEventHelper
    }

    private fun post(what: Int) {
        val context = context
        if (mDialog == null || window == null) return
        //如果Context为Activity，则检查是否被销毁
        if (context is Activity && (context.isFinishing || context.isDestroyed)) return
        try {
            when (what) {
                0 -> mDialog?.show()                            // 显示对话框
                1 -> mDialog?.hide()                            // 隐藏对话框
                2 -> mDialog?.cancel()                          // 取消对话框
                3 -> mDialog?.dismiss()                         // 关闭对话框
                4 -> DialogQueue.get().addQueue(this)    // 添加至对话框队列
                5 -> mDialog?.create()                          // 创建Dialog
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 检查 Dialog 是否正在显示。
     *
     * @return 如果 Dialog 正在显示，则为 true；否则为 false。
     */
    open val isShowing: Boolean get() = mDialog?.isShowing == true

    /**
     * 获取 Dialog 对象。
     *
     * @return Dialog 对象，或者 null。
     */
    open fun get(): Dialog? {
        return mDialog
    }

    /**
     * 创建 Dialog。
     *
     * @return DialogOption 对象本身，用于链式调用。
     */
    open fun create(): DialogOption? {
        post(5)
        return this
    }

    /**
     * 显示 Dialog。
     */
    open fun show() {
        post(0)
    }

    /**
     * 将 Dialog 添加到队列中，以便按顺序显示。
     */
    open fun showByQueue() {
        post(4)
    }

    /**
     * 隐藏 Dialog。
     */
    open fun hide() {
        post(1)
    }

    /* Override Start */

    override fun cancel() {
        post(2)
    }

    override fun dismiss() {
        post(3)
    }

    override fun onCancel(dialog: DialogInterface?) {
        mOnCancelListeners.values.forEach { it.onCancel(dialog) }
    }

    override fun onDismiss(dialog: DialogInterface?) {
        mOnDismissListeners.values.forEach { it.onDismiss(dialog) }
    }

    override fun onKey(dialog: DialogInterface?, keyCode: Int, event: KeyEvent): Boolean {
        mOnKeyListeners.values.forEach { it.onKey(dialog, keyCode, event) }
        return false
    }

    override fun onShow(dialog: DialogInterface?) {
        window?.decorView?.getLocationOnScreen(mViewXY)
        mDialogTouchEventHelper.apply {
            initDecoViewLocation(decorViewX, decorViewY)
            initDecoViewSize(widthByDecorView, heightByDecorView)
        }
        mOnShowListeners.values.forEach { it.onShow(dialog) }
        //缓存Dialog原始尺寸
        defaultDialogSize.x = window?.attributes?.width ?: DIALOG_INVALID_SIZE
        defaultDialogSize.y = window?.attributes?.height ?: DIALOG_INVALID_SIZE
    }

    // --- Dialog 相关方法 ---

    /**
     * 获取 Dialog 的 ActionBar。
     *
     * @return ActionBar 对象，如果 Dialog 没有 ActionBar 则返回 null。
     */
    override fun getActionBar(): ActionBar? {
        return mDialog?.actionBar
    }

    /**
     *  获取当前拥有焦点的 View。
     *
     *  @return 当前拥有焦点的 View，如果没有则返回 null。
     */
    override fun getCurrentFocus(): View? {
        return mDialog?.currentFocus
    }

    /**
     * 获取用于加载布局的 LayoutInflater。
     *
     * @return LayoutInflater 对象。
     */
    override fun getLayoutInflater(): LayoutInflater? {
        return mDialog?.layoutInflater
    }

    /**
     * 打开 Dialog 的选项菜单。
     */
    override fun openOptionsMenu() {
        mDialog?.openOptionsMenu()
    }

    /**
     * 关闭 Dialog 的选项菜单。
     */
    override fun closeOptionsMenu() {
        mDialog?.closeOptionsMenu()
    }

    /**
     * 使 Dialog 的选项菜单失效，下次显示时会重新创建。
     */
    override fun invalidateOptionsMenu() {
        mDialog?.invalidateOptionsMenu()
    }

    /**
     * 为指定的 View 注册上下文菜单。
     *
     * @param view 要注册上下文菜单的 View。
     */
    override fun registerForContextMenu(view: View) {
        mDialog?.registerForContextMenu(view)
    }

    /**
     * 为指定的 View 取消注册上下文菜单。
     *
     * @param view 要取消注册上下文菜单的 View。
     */
    override fun unregisterForContextMenu(view: View) {
        mDialog?.unregisterForContextMenu(view)
    }

    /**
     * 打开指定 View 的上下文菜单。
     *
     * @param view 要打开上下文菜单的 View。
     */
    override fun openContextMenu(view: View) {
        mDialog?.openContextMenu(view)
    }

    /**
     * 设置 Dialog 是否捕获所有的按键事件。
     *
     * @param get 如果 Dialog 应该捕获所有按键事件，则为 true；否则为 false。
     */
    override fun takeKeyEvents(get: Boolean) {
        mDialog?.takeKeyEvents(get)
    }

    // --- 其他重写方法 ---

    /**
     * 分发触摸事件。
     *
     * @param ev 触摸事件。
     * @return 如果事件被消费，则返回 true；否则返回 false。
     */
    override fun dispatchTouchEvent(ev: MotionEvent): Boolean { return false }

    /**
     * 分发按键事件。
     *
     * @param event 按键事件。
     * @return 如果事件被消费，则返回 true；否则返回 false。
     */
    override fun dispatchKeyEvent(event: KeyEvent): Boolean { return false }

    /**
     * 分发按键快捷键事件。
     *
     * @param event 按键快捷键事件。
     * @return 如果事件被消费，则返回 true；否则返回 false。
     */
    override fun dispatchKeyShortcutEvent(event: KeyEvent): Boolean { return false }

    /**
     * 分发轨迹球事件。
     *
     * @param ev 轨迹球事件。
     * @return 如果事件被消费，则返回 true；否则返回 false。
     */
    override fun dispatchTrackballEvent(ev: MotionEvent): Boolean{ return false }

    /**
     * 分发通用运动事件。
     *
     * @param ev 通用运动事件。
     * @return 如果事件被消费，则返回 true；否则返回 false。
     */
    override fun dispatchGenericMotionEvent(ev: MotionEvent): Boolean{ return false }

    /**
     * 分发填充辅助功能事件。
     *
     * @param event 辅助功能事件。
     * @return 如果事件被消费，则返回 true；否则返回 false。
     */
    override fun dispatchPopulateAccessibilityEvent(event: AccessibilityEvent): Boolean{ return false }

    /**
     * 创建面板视图。
     *
     * @param featureId 面板的特征 ID。
     * @return 面板视图，或者 null。
     */
    override fun onCreatePanelView(featureId: Int): View? { return null }

    /**
     * 创建面板菜单。
     *
     * @param featureId 面板的特征 ID。
     * @param menu 菜单。
     * @return 如果菜单被创建，则返回 true；否则返回 false。
     */
    override fun onCreatePanelMenu(featureId: Int, menu: Menu): Boolean{ return false }

    /**
     * 准备面板。
     *
     * @param featureId 面板的特征 ID。
     * @param view 面板视图。
     * @param menu 菜单。
     * @return 如果面板被准备，则返回 true；否则返回 false。
     */
    override fun onPreparePanel(featureId: Int, view: View?, menu: Menu): Boolean{ return false }

    /**
     * 菜单打开时调用。
     *
     * @param featureId 菜单的特征 ID。
     * @param menu 菜单。
     * @return 如果菜单被处理，则返回 true；否则返回 false。
     */
    override fun onMenuOpened(featureId: Int, menu: Menu): Boolean{ return false }

    /**
     * 菜单项被选中时调用。
     *
     * @param featureId 菜单的特征 ID。
     * @param item 被选中的菜单项。
     * @return 如果菜单项被处理，则返回 true；否则返回 false。
     */
    override fun onMenuItemSelected(featureId: Int, item: MenuItem): Boolean{ return false }

    /**
     * 窗口属性改变时调用。
     *
     * @param params 新的窗口属性。
     */
    override fun onWindowAttributesChanged(params: WindowManager.LayoutParams?) {}

    /**
     * 内容改变时调用。
     */
    override fun onContentChanged() {}

    /**
     * 窗口焦点改变时调用。
     *
     * @param hasFocus 如果窗口获得焦点，则为 true；否则为 false。
     */
    override fun onWindowFocusChanged(hasFocus: Boolean) {}

    /**
     * 附加到窗口时调用。
     */
    override fun onAttachedToWindow() {}

    /**
     * 从窗口分离时调用。
     */
    override fun onDetachedFromWindow() {}

    /**
     * 面板关闭时调用。
     *
     * @param featureId 面板的特征 ID。
     * @param menu 菜单。
     */
    override fun onPanelClosed(featureId: Int, menu: Menu) {}

    /**
     * 请求搜索时调用。
     *
     * @param searchEvent 搜索事件。
     * @return 如果搜索请求被处理，则返回 true；否则返回 false。
     */
    override fun onSearchRequested(searchEvent: SearchEvent): Boolean { return false }

    /**
     * 请求搜索时调用。
     *
     * @return 如果搜索请求被处理，则返回 true；否则返回 false。
     */
    override fun onSearchRequested(): Boolean { return false }

    /**
     * 窗口开始动作模式时调用。
     *
     * @param callback 动作模式回调。
     * @return 动作模式，或者 null。
     */
    override fun onWindowStartingActionMode(callback: ActionMode.Callback?): ActionMode? { return null }

    /**
     * 窗口开始动作模式时调用。
     *
     * @param callback 动作模式回调。
     * @param type 动作模式类型。
     * @return 动作模式，或者 null。
     */
    override fun onWindowStartingActionMode(callback: ActionMode.Callback?, type: Int): ActionMode? { return null }

    /**
     * 动作模式开始时调用。
     *
     * @param mode 动作模式。
     */
    override fun onActionModeStarted(mode: ActionMode?) {}

    /**
     * 动作模式结束时调用。
     *
     * @param mode 动作模式。
     */
    override fun onActionModeFinished(mode: ActionMode?) {}

    /**
     * 按键按下时调用。
     *
     * @param keyCode 按键代码。
     * @param event 按键事件。
     * @return 如果按键事件被处理，则返回 true；否则返回 false。
     */
    override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { return false }

    /**
     * 按键长按时调用。
     *
     * @param keyCode 按键代码。
     * @param event 按键事件。
     * @return 如果按键事件被处理，则返回 true；否则返回 false。
     */
    override fun onKeyLongPress(keyCode: Int, event: KeyEvent): Boolean { return false }

    /**
     * 按键抬起时调用。
     *
     * @param keyCode 按键代码。
     * @param event 按键事件。
     * @return 如果按键事件被处理，则返回 true；否则返回 false。
     */
    override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean { return false }

    /**
     * 多个按键按下时调用。
     *
     * @param keyCode 按键代码。
     * @param repeatCount 重复次数。
     * @param event 按键事件。
     * @return 如果按键事件被处理，则返回 true；否则返回 false。
     */
    override fun onKeyMultiple(keyCode: Int, repeatCount: Int, event: KeyEvent): Boolean { return false }

    /**
     * 创建上下文菜单时调用。
     *
     * @param menu 上下文菜单。
     * @param v 触发上下文菜单的视图。
     * @param menuInfo 上下文菜单信息。
     */
    override fun onCreateContextMenu(menu: ContextMenu?, v: View?, menuInfo: ContextMenu.ContextMenuInfo?) {}

    /**
     * 创建 Dialog 时调用。
     *
     * @param savedInstanceState 保存的状态。
     */
    override fun onCreate(savedInstanceState: Bundle?) {
        mDialogConfig?.dialogLifecycle?.onCreate( this, savedInstanceState )
        val cfg = mDialogConfig ?: return
        mDialog?.setContentView( cfg.root )
        mDialogConfig?.buildAttributes( buildLayoutParams )
        mDialogConfig?.dialogLifecycle?.onViewCreate( this, savedInstanceState )
    }

    /**
     * Dialog 开始时调用。
     */
    override fun onStart() {
        mDialogConfig?.dialogLifecycle?.onStart( this )
    }

    /**
     * Dialog 停止时调用。
     */
    override fun onStop() {
        mDialogConfig?.dialogLifecycle?.onStop( this )
    }

    /**
     * 保存 Dialog 状态时调用。
     *
     * @return 保存的状态。
     */
    override fun onSaveInstanceState(outState: Bundle?): Bundle? {
        return mDialogConfig?.dialogLifecycle?.onSaveInstanceState( this, outState )
    }

    /**
     * 恢复 Dialog 状态时调用。
     *
     * @param savedInstanceState 保存的状态。
     */
    override fun onRestoreInstanceState(savedInstanceState: Bundle) {
        mDialogConfig?.dialogLifecycle?.onRestoreInstanceState( this, savedInstanceState )
    }

    /**
     * 按下返回键时调用。
     */
    override fun onBackPressed() {}

    /**
     * 按键快捷键按下时调用。
     *
     * @param keyCode 按键代码。
     * @param event 按键事件。
     * @return 如果按键事件被处理，则返回 true；否则返回 false。
     */
    override fun onKeyShortcut(keyCode: Int, event: KeyEvent): Boolean { return false }

    /**
     * 轨迹球事件发生时调用。
     *
     * @param event 轨迹球事件。
     * @return 如果事件被处理，则返回 true；否则返回 false。
     */
    override fun onTrackballEvent(event: MotionEvent): Boolean { return false }

    /**
     * 通用运动事件发生时调用。
     *
     * @param event 通用运动事件。
     * @return 如果事件被处理，则返回 true；否则返回 false。
     */
    override fun onGenericMotionEvent(event: MotionEvent): Boolean { return false }

    /**
     * 创建选项菜单时调用。
     *
     * @param menu 选项菜单。
     * @return 如果菜单被创建，则返回 true；否则返回 false。
     */
    override fun onCreateOptionsMenu(menu: Menu): Boolean { return false }

    /**
     * 准备选项菜单时调用。
     *
     * @param menu 选项菜单。
     * @return 如果菜单被准备，则返回 true；否则返回 false。
     */
    override fun onPrepareOptionsMenu(menu: Menu): Boolean { return false }

    /**
     * 选项菜单项被选中时调用。
     *
     * @param item 被选中的菜单项。
     * @return 如果菜单项被处理，则返回 true；否则返回 false。
     */
    override fun onOptionsItemSelected(item: MenuItem): Boolean { return false }

    /**
     * 选项菜单关闭时调用。
     *
     * @param menu 选项菜单。
     */
    override fun onOptionsMenuClosed(menu: Menu) {}

    /**
     * 上下文菜单项被选中时调用。
     *
     * @param item 被选中的菜单项。
     * @return 如果菜单项被处理，则返回 true；否则返回 false。
     */
    override fun onContextItemSelected(item: MenuItem): Boolean { return false }

    /**
     * 上下文菜单关闭时调用。
     *
     * @param menu 上下文菜单。
     */
    override fun onContextMenuClosed(menu: Menu) {}

    /* Override End */

    /**
     * 将 View 绘制成 Bitmap。
     *
     * @param view 要绘制的 View。
     * @return Bitmap 对象，或者 null。
     */
    fun drawToBitmap(view: View): Bitmap? {
        return view.drawToBitmap()
    }

    /**
     * 为 View 添加点击缩放动画。
     *
     * @param v 要添加动画的 View。
     * @param ev 触摸事件。
     * @param downScaleValue 按下时的缩放比例。
     */
    @JvmOverloads
    fun onTouchScaleAnimation(v: View?, ev: MotionEvent?, downScaleValue: Float = 0.98F) {
        Utils.onTouchScaleAnimation(v, ev, downScaleValue)
    }

    /**
     * 创建一个 PopupWindow。
     *
     * @param view PopupWindow 中显示的 View。
     * @return PopupWindow 对象。
     */
    fun createPopupWindow(view: View): PopupWindow {
        return Utils.createPopupWindow(view)
    }

    /**
     * 获取字符串资源的值。
     *
     * @param resId 字符串资源 ID。
     * @return 字符串值，或者 null。
     */
    fun getString(@StringRes resId: Int): String? {
        return try {
            context?.resources?.getString(resId)
        } catch (e: Exception) {
            null
        }
    }

    /**
     * 获取颜色资源的值。
     *
     * @param resId 颜色资源 ID。
     * @return 颜色值，或者 null。
     */
    fun getColor(@ColorRes resId: Int): Int? {
        return try {
            (if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                context?.resources?.getColor(resId, null)
            } else {
                context?.resources?.getColor(resId)
            })
        } catch (e: Exception) {
            0
        }
    }

    /**
     * 将 dp 值转换为像素值（Int）。
     *
     * @param dp dp 值。
     * @return 像素值。
     */
    @JvmName("dp2PxByInt")
    fun dp2Px(dp: Int): Int {
        return mDialogConfig?.dp2Px(dp) ?: 0
    }

    /**
     * 将 dp 值转换为像素值（Float）。
     *
     * @param dp dp 值。
     * @return 像素值。
     */
    @JvmName("dp2PxByFloat")
    fun dp2Px(dp: Float): Float {
        return mDialogConfig?.dp2Px(dp) ?: 0F
    }
}